<?php
/**
 * Created by PhpStorm.
 * User: longli
 * VX: isa1589518286
 * Date: 2020/09/14
 * Time: 17:06
 * @link http://www.lmterp.cn
 */

namespace app\common\service\product;

use app\common\library\Tools;
use app\common\model\ProductStore;
use app\common\model\Warehouse;
use app\common\model\WarehouseAllot;
use app\common\model\WarehouseArea;
use app\common\model\WarehouseBorrow;
use app\common\model\WarehouseCheck;
use app\common\model\WarehouseLocation;
use app\common\model\WarehouseShelf;
use app\common\model\WarehouseStock;
use app\common\model\WarehouseTerpInfo;
use app\common\service\BaseService;
use app\common\status\BaseStatus;
use think\Db;
use think\exception\DbException;
use think\facade\Log;

class WarehouseService extends BaseService
{
    /**
     * 添加仓库
     * @param array $data 仓库信息
     * @return Warehouse|bool
     * @date 2020/09/18
     * @author longli
     */
    public function addWarehouse($data = [])
    {
        $wData = Warehouse::getFilterField($data, '');
        if(empty($wData)) return false;
        $wData = Tools::trim($wData);
        $w = null;
        if(isset($wData['warehouse_id'])) $w = Warehouse::get($wData['warehouse_id']);
        if(!empty($w))
        {
            $w->save($wData);
        }
        else
        {
            $w = Warehouse::create($wData)->refresh();
        }
        if(!empty($wData['is_default'])) Warehouse::setDefault($w, true);
        return $w;
    }

    /**
     * 初始化商品库存
     * @param int|ProductStore $store 变体id, 或者变体
     * @param array $data 库存信息
     * @return WarehouseStock|bool
     * @date 2020/09/16
     * @author longli
     */
    public function addStock($store, $data = [])
    {
        $store = ProductStore::getObj($store);
        if(empty($store)) return false;
        $sData = WarehouseStock::getFilterField($data, '');
        if(empty($sData)) return false;
        $sData = Tools::trim($sData);
        $sData['store_id'] = $store->store_id;
        $sData['sku'] = $store->sku;
        $sData['price'] = $store->price;
        $sData['image_url'] = $store->image_url;
        $stock = null;
        if(isset($sData['stock_id'])) $stock = WarehouseStock::get($sData['stock_id']);
        if(empty($stock) && !empty($sData['warehouse_id']))
            $stock = WarehouseStock::get(['warehouse_id' => $sData['warehouse_id'], 'store_id' => $store->store_id]);
        try
        {
            Db::startTrans();
            if(!empty($stock))
            {
                if(isset($data['location_id']) && $data['location_id'] != $stock->location_id)
                {
                    WarehouseLocation::releaseUsed($stock->location_id);
                    WarehouseLocation::used($data['location_id']);
                }
                // 限制可修改字段
                $stock->save(Tools::visibleArray(['min_stock', 'max_stock', 'location_id', 'status', 'remark'], $sData));
            }
            else
            {
                $stock = WarehouseStock::create($sData)->refresh();
                // 添加初始化库存日志
                if($stock->stock > 0)
                {
                    StockService::stockInfoLog($stock->warehouse_id, $stock->sku, $stock->stock, $stock->price, [
                        'ref_type' => BaseStatus::REF_TYPE_PRODUCT,
                        'ref_id_type' => ProductStore::getTable(),
                        'type' => $store->store_id,
                        'ref_sn' => $store->store_id,
                        'user_id' => $store->create_by,
                        'remark' => '初始化入库',
                    ]);
                }
            }
            Db::commit();
            return $stock;
        }catch(DbException $e)
        {
            Log::info(sprintf("录用库存失败，错误信息【%s】", $e->getMessage()));
            Db::rollback();
            return false;
        }
    }

    /**
     * 添加盘点单
     * @param array $data
     * @return WarehouseCheck|false
     * @date 2021/02/10
     * @author longli
     */
    public function addCheck($data = [])
    {
        $cData = WarehouseCheck::getFilterField($data, '');
        if(empty($cData)) return false;
        $cData = Tools::trim($cData);
        $check = null;
        if(isset($cData['check_id'])) $check = WarehouseCheck::get($cData['check_id']);
        if(empty($check) && isset($cData['check_sn'])) $check = WarehouseCheck::get(['check_sn' => $cData['check_sn']]);
        if(!empty($check))
        {
            $check->save($cData);
        }
        else
        {
            $cData['check_sn'] = $this->generateCheckSn();
            $check = WarehouseCheck::create($cData)->refresh();
        }
        return $check;
    }

    /**
     * 生成盘点单号
     * @return string
     * @date 2021/02/10
     * @author longli
     */
    public function generateCheckSn()
    {
        return self::generateSn('CK');
    }

    /**
     * 生成调拨单号
     * @return string 调拨单号
     * @date 2021/01/01
     * @author longli
     */
    public function generateAllotSn()
    {
        return self::generateSn('AL');
    }

    /**
     * 生成借用单号
     * @return string
     * @date 2021/01/04
     * @author longli
     */
    public function generateBorrowSn()
    {
        return self::generateSn('BR');
    }

    /**
     * 添加调拨单
     * @param array $data 调拨详情
     * @param array $info 调拨详情
     * @return WarehouseAllot|bool
     * @date 2021/02/18
     * @author longli
     */
    public function addAllot($data = [], $info = [])
    {
        $aData = WarehouseAllot::getFilterField($data, '');
        if(empty($aData)) return false;
        $aData = Tools::trim($aData);
        $allot = null;
        if(isset($aData['allot_id'])) $allot = WarehouseAllot::get($aData['allot_id']);
        if(empty($allot) && isset($aData['allot_sn'])) $allot = WarehouseAllot::get(['allot_sn' => $aData['allot_sn']]);
        if(!empty($allot))
        {
            // 限制更新字段
            $aData = Tools::visibleArray(['status', 'logistics_name', 'track_num', 'express_id', 'logistics_price','remark'], $aData);
            if(empty($aData)) return $allot;
            $allot->save($aData);
        }
        else
        {
            try
            {
                Db::startTrans();
                $aData['allot_sn'] = $this->generateAllotSn();
                $allot = WarehouseAllot::create($aData)->refresh();
                if(!empty($info) && !isset($info[0])) $info = [$info];
                foreach($info as $item)
                {
                    $item += [
                        'id_type' => WarehouseAllot::getTable(),
                        'ref_id' => $allot->allot_id,
                    ];
                    $stock = WarehouseStock::getWarehouseBySku($allot->out_id, $item['sku']);
                    $this->addInfo($item, $stock);
                }
                Db::commit();
            }catch (DbException $exception)
            {
                Log::info(sprintf("添加调拨单失败，错误信息【%s】", $exception->getMessage()));
                Db::rollback();
                return false;
            }
        }
        return $allot;
    }

    /**
     * 添加借用单
     * @param array $data 调拨详情
     * @param array $info 借用详情
     * @return WarehouseBorrow|bool
     * @date 2021/02/18
     * @author longli
     */
    public function addBorrow($data = [], $info = [])
    {
        $bData = WarehouseBorrow::getFilterField($data, '');
        if(empty($bData)) return false;
        $bData = Tools::trim($bData);
        $borrow = null;
        if(isset($bData['borrow_id'])) $borrow = WarehouseBorrow::get($bData['borrow_id']);
        if(empty($borrow) && isset($bData['borrow_sn'])) $borrow = WarehouseBorrow::get(['borrow_sn' => $bData['borrow_sn']]);
        if(!empty($borrow))
        {
            // 限制更新字段
            $bData = Tools::visibleArray(['status', 'borrow_date', 'remark'], $bData);
            if(empty($bData)) return $borrow;
            $borrow->save($bData);
        }
        else
        {
            try
            {
                Db::startTrans();
                $bData['borrow_sn'] = $this->generateBorrowSn();
                $borrow = WarehouseBorrow::create($bData)->refresh();
                if(!empty($info) && !isset($info[0])) $info = [$info];
                foreach($info as $item)
                {
                    $item += [
                        'id_type' => WarehouseBorrow::getTable(),
                        'ref_id' => $borrow->borrow_id,
                    ];
                    $stock = WarehouseStock::getWarehouseBySku($borrow->out_id, $item['sku']);
                    $this->addInfo($item, $stock);
                }
                Db::commit();
            }catch(DbException $exception)
            {
                Log::info(sprintf("添加借用单失败，错误信息【%s】", $exception->getMessage()));
                Db::rollback();
                return false;
            }

        }
        return $borrow;
    }

    /**
     * 添加仓库区域
     * @param array $data
     * @return WarehouseArea|false
     * @date 2021/02/18
     * @author longli
     */
    public function addArea($data = [])
    {
        $aData = WarehouseArea::getFilterField($data, '');
        if(empty($aData)) return false;
        $aData = Tools::trim($aData);
        $area = null;
        if(isset($aData['area_id'])) $area = WarehouseArea::get($aData['area_id']);
        if(!empty($area))
        {
            $area->save($aData);
        }
        else
        {
            $area = WarehouseArea::create($aData)->refresh();
        }
        return $area;
    }

    /**
     * 添加库位
     * @param array $data 库位详情
     * @return WarehouseLocation|bool
     * @date 2021/02/18
     * @author longli
     */
    public function addLocation($data = [])
    {
        $nData = WarehouseLocation::getFilterField($data, '');
        if(empty($nData)) return false;
        $nData = Tools::trim($nData);
        $location = null;
        if(isset($nData['location_id'])) $location = WarehouseLocation::get($nData['location_id']);
        if(!empty($location))
        {
            if(empty($nData)) return $location;
            $location->save($nData);
        }
        else
        {
            $location = WarehouseLocation::create($nData)->refresh();
        }
        return $location;
    }

    /**
     * 添加货架
     * @param array $data 货架详情
     * @return WarehouseShelf|bool
     * @date 2021/02/18
     * @author longli
     */
    public function addShelf($data = [])
    {
        $sData = WarehouseShelf::getFilterField($data, '');
        if(empty($sData)) return false;
        $sData = Tools::trim($sData);
        $shelf = null;
        if(isset($sData['shelf_id'])) $shelf = WarehouseShelf::get($sData['shelf_id']);
        if(!empty($shelf))
        {
            // 限制更新字段
            $sData = Tools::visibleArray(['status', 'area_id', 'remark', 'level'], $sData);
            if(empty($sData)) return $shelf;
            $shelf->save($sData);
        }
        else
        {
            $shelf = WarehouseShelf::create($sData)->refresh();
        }
        $area = $shelf->area;
        $area->shelf_qty = $area->shelf()->whereIn('status', [
            WarehouseShelf::STATUS_ASS, WarehouseShelf::STATUS_USED,
            WarehouseShelf::STATUS_FULL
        ])->count();
        $area->save();
        return $shelf;
    }

    /**
     * 添加仓库商品关联详情
     * @param string[] $data 商品信息
     * @param WarehouseStock $stock 库存信息
     * @return WarehouseTerpInfo|bool
     * @date 2021/02/19
     * @author longli
     */
    public function addInfo($data = [], $stock = null)
    {
        $iData = WarehouseTerpInfo::getFilterField($data, '');
        if(empty($iData) || (isset($iData['qty']) && $iData['qty'] < 1)) return false;
        $iData = Tools::trim($iData);
        $terpInfo = null;
        if(isset($iData['info_id'])) $terpInfo = WarehouseTerpInfo::get($iData['info_id']);
        if(empty($terpInfo) && isset($iData['id_type']) && isset($iData['ref_id']) && isset($iData['sku']))
            $terpInfo = WarehouseTerpInfo::get(['id_type' => $iData['id_type'], 'ref_id' => $iData['ref_id'], 'sku' => $iData['sku']]);
        if(!empty($stock))
        {
            $iData = array_merge($iData, [
                'warehouse_id' => $stock->warehouse_id,
                'store_id' => $stock->store_id,
                'price' => $stock->price,
                'image_url' => $stock->image_url,
                'sku' => $stock->sku,
            ]);
        }
        if(!empty($terpInfo))
        {
            $terpInfo->save($iData);
        }
        else
        {
            $terpInfo = WarehouseTerpInfo::create($iData)->refresh();
        }
        return $terpInfo;
    }

    /**
     * 按仓库区域/货架/库位 排序sku
     * @param int|Warehouse $warehouse
     * @param array $data sku 信息
     * @example [
     *      [
     *          'sku' => 'A001'
     *      ]
     * ]
     * @return array
     * @date 2021/04/05
     * @author longli
     */
    public function sortSkuByWarehouse($warehouse, $data = [])
    {
        // 商业旗舰版功能
        return $data;
    }
}